#include "xmlrpc.h"
#include "xmlrpctypes.h"
#include <imcvcodc.h>

using namespace XmlRpc;

EXPORT_C CValue::~CValue() { }

EXPORT_C void CValue::AppendXmlToBufL(RBuf8& aBuf) const
	{
	DoAppendXmlToBufL(aBuf);
	}

void CValue::InsureSpaceL(RBuf8& aBuf, TInt aCharacters) const
	{
	if (aBuf.Length() + aCharacters > aBuf.MaxLength())
		aBuf.ReAllocL(aBuf.MaxLength() + (KGrowIncrement > aCharacters ? KGrowIncrement : aCharacters));
	}

const TInt KMaxSimpleSize = 32;
const TInt KMaxMediumSize = 64;

EXPORT_C void CInt::DoAppendXmlToBufL(RBuf8& aBuf) const
	{
	_LIT8(KFormat, "<int>%d</int>");
	InsureSpaceL(aBuf, KMaxSimpleSize);
	aBuf.AppendFormat(KFormat, iVal);
	}

EXPORT_C void CBoolean::DoAppendXmlToBufL(RBuf8& aBuf) const
	{
	_LIT8(KFormat, "<boolean>%d</boolean>");
	InsureSpaceL(aBuf, KMaxSimpleSize);
	aBuf.AppendFormat(KFormat, iVal);
	}

EXPORT_C void CDouble::DoAppendXmlToBufL(RBuf8& aBuf) const
	{
	_LIT8(KFormat, "<double>%f</double>");
	InsureSpaceL(aBuf, KMaxSimpleSize);
    aBuf.AppendFormat(KFormat, iVal);
	}

EXPORT_C void CDateTime::DoAppendXmlToBufL(RBuf8& aBuf) const
	{
	_LIT8(KFormat, "<dateTime.iso8601>%+04d%+02d%+02dT%+02d:%+02d:%+02d</dateTime.iso8601>");
	InsureSpaceL(aBuf, KMaxMediumSize);
    aBuf.AppendFormat(KFormat, iVal.Year(), iVal.Month() + 1, iVal.Day() + 1, iVal.Hour(), iVal.Minute(), iVal.Second());
	}


EXPORT_C CString* CString::NewL(const TDesC& aVal)
	{
	CString* s = new(ELeave) CString(aVal);
	CleanupStack::PushL(s);
	s->ConstructL(aVal);
	CleanupStack::Pop();
	return s;
	}
	
EXPORT_C void CString::SetL(const TDesC& aVal)
	{
	if (iString.MaxLength() < aVal.Length())
		iString.ReAllocL(aVal.Length());
	iString.Copy(aVal);
	}

EXPORT_C const TDesC& CString::Get() const
	{
	return iString;
	}
	
EXPORT_C CString::~CString()
	{
	iString.Close();
	}

CString::CString(const TDesC& /*aVal*/)
	: CValue(EString)
	{
	}

void CString::ConstructL(const TDesC& aVal)
	{
	iString.CreateL(aVal);
	}

EXPORT_C void CString::DoAppendXmlToBufL(RBuf8& aBuf) const
	{
	_LIT8(KFormat, "<string>%S</string>");
	InsureSpaceL(aBuf, KMaxSimpleSize + iString.Length());
	RBuf8 stringUtf8;
	XmlEncoding::EncodeL(iString, stringUtf8);
	
	TPtrC8 ptr = stringUtf8.Mid(0);
    aBuf.AppendFormat(KFormat, &ptr);
	stringUtf8.Close();
	}


EXPORT_C CStruct* CStruct::NewL()
	{
	return new(ELeave)CStruct();
	}

EXPORT_C void CStruct::SetL(const TDesC8& aKey, CValue* aMember)
	{
	CStruct::TStructKey key(aKey);
	iMembers.InsertL(key, aMember);
	}

EXPORT_C CValue* CStruct::GetL(const TDesC8& aKey) const
	{
	CStruct::TStructKey key(aKey);
	return iMembers.FindL(key);
	}

EXPORT_C CValue* CStruct::RemoveL(const TDesC8& aKey)
	{
	CStruct::TStructKey key(aKey);
	CValue* val = iMembers.FindL(key);
	iMembers.Remove(key); // no need to check return val, as FindL will leave if not found
	return val;
	}

EXPORT_C CStruct::~CStruct()
	{
	THashMapIter<const CStruct::TStructKey, CValue*> iter(iMembers);
	while (iter.NextKey() != NULL)
		{
		CValue* val = *iter.CurrentValue();
		iter.RemoveCurrent();
		delete val;
		}
	// need to clean up keys and members
	iMembers.Close();
	}
	
EXPORT_C void CStruct::DoAppendXmlToBufL(RBuf8& aBuf) const
	{
	_LIT8(KOpenStruct, "<struct>");
	_LIT8(KCloseStruct, "</struct>");
	_LIT8(KOpenMemberFormat, "<member><name>%S</name><value>");
	_LIT8(KCloseMember, "</value></member>");
	
	InsureSpaceL(aBuf, KOpenStruct().Length());
	aBuf.Append(KOpenStruct);
	
	THashMapIter<const CStruct::TStructKey, CValue*> iter(iMembers);
	while (iter.NextKey() != NULL)
		{
		const CStruct::TStructKey& key = *iter.CurrentKey();
		CValue* val = *iter.CurrentValue();
		InsureSpaceL(aBuf, KOpenMemberFormat().Length() + key.Length());
		aBuf.AppendFormat(KOpenMemberFormat, &key);
		val->AppendXmlToBufL(aBuf);
		InsureSpaceL(aBuf, KCloseMember().Length());
		aBuf.Append(KCloseMember);
		}

	InsureSpaceL(aBuf, KCloseStruct().Length());
	aBuf.Append(KCloseStruct);
	}


TUint32 HBufCHash(const CStruct::TStructKey &aBuf)
	{
	return DefaultHash::Des8 (aBuf);
	}

TBool HBufCIdent(const CStruct::TStructKey &aL, const CStruct::TStructKey &aR)
	{
	return DefaultIdentity::Des8 (aL, aR);
	}

CStruct::CStruct()
	: CValue(EStruct), iMembers(THashFunction32<const CStruct::TStructKey>(&HBufCHash), TIdentityRelation<const CStruct::TStructKey>(&HBufCIdent))
	{
	}

EXPORT_C CArray* CArray::NewL()
	{
	return new(ELeave) CArray();
	}

EXPORT_C void CArray::InsertL(CValue* aVal, TInt aIndex)
	{
	iArray.InsertL(aVal, aIndex);
	}

EXPORT_C void CArray::AppendL(CValue* aVal)
	{
	iArray.AppendL(aVal);
	}

EXPORT_C TInt CArray::Count() const
	{
	return iArray.Count();
	}

EXPORT_C CValue* CArray::Get(TInt aIndex) const
	{
	ASSERT(aIndex < iArray.Count());
	return iArray[aIndex];
	}

EXPORT_C CValue* CArray::RemoveL(TInt aIndex)
	{
	ASSERT(aIndex < iArray.Count());
	CValue* v = iArray[aIndex];
	iArray.Remove(aIndex);
	return v;
	}

EXPORT_C CArray::~CArray()
	{
	iArray.ResetAndDestroy();
	}
	
EXPORT_C void CArray::DoAppendXmlToBufL(RBuf8& aBuf) const
	{
	_LIT8(KOpenArray, "<array><data>");
	_LIT8(KCloseArray, "</data></array>");
	_LIT8(KOpenValue, "<value>");
	_LIT8(KCloseValue, "</value>");
	
	InsureSpaceL(aBuf, KOpenArray().Length());
	aBuf.Append(KOpenArray);
	
	for (TInt i = 0; i < iArray.Count(); i++)
		{
		InsureSpaceL(aBuf, KOpenValue().Length());
		aBuf.Append(KOpenValue);
		iArray[i]->AppendXmlToBufL(aBuf);
		InsureSpaceL(aBuf, KCloseValue().Length());
		aBuf.Append(KCloseValue);
		}

	InsureSpaceL(aBuf, KCloseArray().Length());
	aBuf.Append(KCloseArray);
	}

CArray::CArray()
	: CValue(EArray)
	{
	}

EXPORT_C CBase64* CBase64::NewL(const TDesC8& aVal)
	{
	CBase64* cb = new (ELeave) CBase64();
	CleanupStack::PushL(cb);
	cb->ConstructL(aVal, EFalse);
	CleanupStack::Pop(cb);
	return cb;
	}

EXPORT_C CBase64* CBase64::NewFromEncodedL(const TDesC8& aVal)
	{
	CBase64* cb = new (ELeave) CBase64();
	CleanupStack::PushL(cb);
	cb->ConstructL(aVal, ETrue);
	CleanupStack::Pop(cb);
	return cb;
	}

EXPORT_C void CBase64::SetL(const TDesC8& aVal)
	{
	if (iString.MaxLength() < aVal.Length())
		iString.ReAllocL(aVal.Length());
	iString.Copy(aVal);	
	}

EXPORT_C const TDesC8& CBase64::Get() const
	{
	return iString;
	}

EXPORT_C const TDesC8& CBase64::GetEncodedL() const
	{
	TImCodecB64 b64;
	b64.Initialise();
	iEncoded.Close();

	iEncoded.CreateL(iString.Length() * 1.4);
	b64.Encode(iString, iEncoded);
	
	return iEncoded;
	}

EXPORT_C CBase64::~CBase64()
	{
	iString.Close();
	iEncoded.Close();
	}

void CBase64::ConstructL(const TDesC8& aVal, TBool aEncoded)
	{
	if (!aEncoded)
		{
		iString.CreateL(aVal);
		}
	else
		{
		TImCodecB64 b64;
		b64.Initialise();

		iEncoded.CreateL(aVal);
		iString.CreateL(iEncoded.Length());
		b64.Decode(iEncoded, iString);
		}
	}

CBase64::CBase64(const TDesC8 &/*aVal*/)
	: CValue(EBase64)
	{
	}

CBase64::CBase64()
	: CValue(EBase64)
	{
	}
	
EXPORT_C void CBase64::DoAppendXmlToBufL(RBuf8& aBuf) const
	{
	_LIT8(KBase64Format, "<base64>%S</base64>");

	const TDesC8& b64buf = GetEncodedL(); 
	InsureSpaceL(aBuf, KMaxSimpleSize + iEncoded.Length());
	aBuf.AppendFormat(KBase64Format, &b64buf);
	}
